home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / windows / winfire / winfire.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-22  |  14.7 KB  |  461 lines

  1. // ------------------------ WINFIRE.C ------------------------------
  2. // Coded bye Jare of Iguana near Xmas of 1994
  3. // Comments to a880104@zipi.fi.upm.es
  4. // My original ASM routine was 200 lines of plain ASM, this Windows
  5. // version goes up to near 500 lines!!
  6. // You can use this for anything you like, but you must credit me.
  7.  
  8. #include <windows.h>
  9. #include <wing.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12.  
  13.     // Fire array size.
  14. #define FIREW 128
  15. #define FIREH  96
  16.     // Nice size for the window. Frame will take some bits apart, however.
  17. #define WINDOWW FIREW*4
  18. #define WINDOWH FIREH*4
  19.  
  20.     // Handy msg structure.
  21. typedef struct {
  22.     HWND    hwnd;
  23.     UINT    msg;
  24.     WPARAM  wParam;
  25.     LPARAM  lParam;
  26. } tMSG, *pMSG;
  27.  
  28.     // Low Level data types.
  29. typedef unsigned char  byte;
  30. typedef unsigned short word;
  31. typedef unsigned long  dword;
  32.  
  33. typedef byte  * Pbyte;
  34. typedef word  * Pword;
  35. typedef dword * Pdword;
  36.  
  37. typedef byte  FAR * LPbyte;
  38. typedef word  FAR * LPword;
  39. typedef dword FAR * LPdword;
  40.  
  41. // ===============================================================
  42. // WinG DC handling functions.
  43.  
  44.     // The stock default bitmap of a WinGDC.
  45. static HBITMAP hBitmapMonochrome = 0;
  46.  
  47.     // Creates a top-down WinGDC with the specified rgb palette.
  48.     // Returns the HDC and stores the bitmap pointer in ppSurfaceBits,
  49.     // if not passed a NULL parameter.
  50.  
  51. static HDC MakeWinGDC(RGBQUAD rgb[256], LPbyte *ppSurfaceBits) {
  52.     HDC     hWinGDC;
  53.     HBITMAP hBitmapNew;
  54.     int     i;
  55.     struct {
  56.         BITMAPINFOHEADER Header;
  57.         RGBQUAD ColorTable[256];
  58.     } Info;
  59.  
  60.         // Force top-down 8-bit bitmap of size FIREW*FIREH.
  61.     Info.Header.biSize         = sizeof(Info.Header);
  62.     Info.Header.biPlanes       = 1;
  63.     Info.Header.biBitCount     = 8;
  64.     Info.Header.biCompression  = BI_RGB;
  65.     Info.Header.biSizeImage    = 0;
  66.     Info.Header.biClrUsed      = 0;
  67.     Info.Header.biClrImportant = 0;
  68.     Info.Header.biWidth        = FIREW;
  69.     Info.Header.biHeight       = -FIREH;    // Minus for top-down.
  70.  
  71.     for (i = 0; i < 256; i++)
  72.         Info.ColorTable[i] = rgb[i];
  73.  
  74.         // Create a WinGDC and Bitmap, then select away DC's default
  75.         // monochrome bitmap.
  76.     hWinGDC = WinGCreateDC();
  77.     if (hWinGDC) {
  78.         hBitmapNew = WinGCreateBitmap(hWinGDC,
  79.                                       (LPBITMAPINFO)&Info,
  80.                                       ppSurfaceBits);
  81.         if (hBitmapNew) {
  82.             hBitmapMonochrome = (HBITMAP)SelectObject(hWinGDC,
  83.                                                       hBitmapNew);
  84.         } else {
  85.             DeleteDC(hWinGDC);
  86.             hWinGDC = 0;
  87.         }
  88.     }
  89.     return hWinGDC;
  90. }
  91.  
  92.     // Finishes the WinGDC. Pretty straightforward.
  93.  
  94. static void EndWinGDC(HDC hWinGDC) {
  95.     HBITMAP hBitmapOld;
  96.  
  97.     if (hWinGDC && hBitmapMonochrome) {
  98.             // Select the stock 1x1 monochrome bitmap back in
  99.         hBitmapOld = (HBITMAP)SelectObject(hWinGDC,
  100.                                            hBitmapMonochrome);
  101.         hBitmapMonochrome = 0;
  102.         DeleteObject(hBitmapOld);
  103.         DeleteDC(hWinGDC);
  104.     }
  105. }
  106.  
  107.     // Creates a palette from the specified colors, but requires
  108.     // using the system colors. Updates 'rgb' to enable the use of an
  109.     // identity palette i.e. on exit, rgb contains the effective
  110.     // palette, that can in turn be used for creating the WinGDC.
  111.  
  112. static HPALETTE CreateIdentityPalette(RGBQUAD aRGB[256], int nColors) {
  113.     int i;
  114.     static struct {
  115.         WORD         Version;
  116.         WORD         NumberOfEntries;
  117.         PALETTEENTRY aEntries[256];
  118.     } pal = {
  119.         0x300,
  120.         256
  121.     };
  122.     HDC hdc;
  123.  
  124.         // For SYSPAL_STATIC, get the twenty static colors into
  125.         // the array, then fill in the empty spaces with the
  126.         // given color table
  127.  
  128.     hdc = GetDC(NULL);
  129.         // Get the static colors
  130.     GetSystemPaletteEntries(hdc, 0,   10, pal.aEntries);
  131.     GetSystemPaletteEntries(hdc, 246, 10, pal.aEntries + 246);
  132.  
  133.         // Set the peFlags of the lower static colors to zero.
  134.         // And copy the static colors to the user palette so
  135.         // the caller knows exactly which palette we created.
  136.     for (i = 0; i < 10; i++) {
  137.         aRGB[i].rgbRed   = pal.aEntries[i].peRed;
  138.         aRGB[i].rgbGreen = pal.aEntries[i].peGreen;
  139.         aRGB[i].rgbBlue  = pal.aEntries[i].peBlue;
  140.         pal.aEntries[i].peFlags = 0;
  141.     }
  142.  
  143.         // Fill in the entries from the given color table
  144.     for (; i < nColors+10; i++) {
  145.         pal.aEntries[i].peRed   = aRGB[i].rgbRed;
  146.         pal.aEntries[i].peGreen = aRGB[i].rgbGreen;
  147.         pal.aEntries[i].peBlue  = aRGB[i].rgbBlue;
  148.         pal.aEntries[i].peFlags = PC_RESERVED;
  149.     }
  150.  
  151.         // Mark any empty entries as PC_RESERVED
  152.     for (; i < 246; i++) {
  153.         aRGB[i].rgbRed   = pal.aEntries[i].peRed;
  154.         aRGB[i].rgbGreen = pal.aEntries[i].peGreen;
  155.         aRGB[i].rgbBlue  = pal.aEntries[i].peBlue;
  156.         pal.aEntries[i].peFlags = PC_RESERVED;
  157.     }
  158.  
  159.         // Set the peFlags of the upper static colors to zero, and
  160.         // copy static colors.
  161.     for (; i < 256; i++) {
  162.         aRGB[i].rgbRed   = pal.aEntries[i].peRed;
  163.         aRGB[i].rgbGreen = pal.aEntries[i].peGreen;
  164.         aRGB[i].rgbBlue  = pal.aEntries[i].peBlue;
  165.         pal.aEntries[i].peFlags = 0;
  166.     }
  167.  
  168.     ReleaseDC(NULL, hdc);
  169.  
  170.         // Create the palette
  171.     return CreatePalette((LOGPALETTE *)&pal);
  172. }
  173.  
  174. // ===============================================================
  175. // Fire algorithm. Pure C, ASM will do it much faster.
  176.  
  177. static void DoFire(Pbyte to, Pbyte from) {
  178.     int i, j;
  179.  
  180.     from += FIREW;
  181.     to   += 0;
  182.  
  183.         // All lines but the first and last. The first will disappear,
  184.         // and the last must be taken with care for the limits of the
  185.         // array.
  186.     for (i = 1; i < FIREH-1; i++) {
  187.             // Leftmost pixel.
  188.         *to++ = (byte)((  (word)from[-1]          + (word)from[1]
  189.                         + (word)from[-(int)FIREW] + (word)from[FIREW]) >> 2);
  190.         from++;
  191.             // Middle pixels.
  192.         for (j = 1; j < FIREW-1; j++) {
  193.             *to++ = (byte)((  (word)from[-1]            + (word)from[1]
  194.                             + (word)from[-(int)FIREW-1] + (word)from[-(int)FIREW+1]
  195.                             + (word)from[+(int)FIREW-1] + (word)from[+(int)FIREW+1]
  196.                             + (word)from[-(int)FIREW]   + (word)from[FIREW]
  197.                            ) >> 3);
  198.             from++;
  199.         }
  200.             // Rightmost pixel.
  201.         *to++ = (byte)((  (word)from[-1]          + (word)from[1]
  202.                         + (word)from[-(int)FIREW] + (word)from[FIREW]) >> 2);
  203.         from++;
  204.     }
  205.         // Bottom line.
  206.     for (j = 0; j < FIREW-1; j++) {
  207.         *to++ = (byte)((  (word)from[-1]          + (word)from[1]
  208.                         + (word)from[-(int)FIREW] + (word)from[0]) >> 2);
  209.         from++;
  210.     }
  211.         // Rightmost pixel of bottom line.
  212.     *to = (byte)(((word)from[-1] + (word)from[-(int)FIREW]) >> 1);
  213. }
  214.  
  215. // ===============================================================
  216. // Fire Window message handlers.
  217.  
  218.     // Global vars.
  219. static HINSTANCE AppInstance;       // ditto.
  220.  
  221. static HDC      ScreenHDC;          // WinGDC created.
  222. static LPbyte   Screen;             // Pointer to the surface bitmap.
  223. static UINT     Timer;              // Timer identifier.
  224. static RGBQUAD  rgb[256];           // Palette used.
  225. static HPALETTE Palette;            // Handle to it.
  226. static int      WindowState;        // Minimized, maximized or normal?
  227. static HICON    FireIcon;           // Handle to icon for QueryDragIcon.
  228.  
  229.     // Fire buffers. FAR so the are in their own data segment.
  230. static byte FireBuf1[FIREW*FIREH], FireBuf2[FIREW*FIREH];
  231. static Pbyte Buf1 = FireBuf1, Buf2 = FireBuf2;
  232.  
  233. // ---------- Message handlers.
  234.  
  235. static LRESULT wmCreate(pMSG msg) {
  236.     int     i;
  237.  
  238.     FireIcon = LoadIcon(AppInstance, "FIREICON");
  239.  
  240.         // Create a smooth palette.
  241.     memset(rgb, 0, sizeof(rgb));
  242.     for (i = 10; i < 10+16; i++)
  243.         rgb[i].rgbRed   = (BYTE)((i-10)*16);
  244.     for (; i < 10+48; i++) {
  245.         rgb[i].rgbRed   = 255;
  246.         rgb[i].rgbGreen = (BYTE)((i-10-16)*8);
  247.     }
  248.     for (; i < 10+80; i++) {
  249.         rgb[i].rgbRed   = 255;
  250.         rgb[i].rgbGreen = 255;
  251.         rgb[i].rgbBlue  = (BYTE)((i-10-48)*8);
  252.     }
  253.     for (; i < 10+236; i++) {
  254.         rgb[i].rgbRed   = 255;
  255.         rgb[i].rgbGreen = 255;
  256.         rgb[i].rgbBlue  = 255;
  257.     }
  258.  
  259.         // Clean up buffers.
  260.     memset(FireBuf1, 0, sizeof(FireBuf1));
  261.     memset(FireBuf2, 0, sizeof(FireBuf2));
  262.  
  263.         // Create stuff.
  264.     Palette   = CreateIdentityPalette(rgb, 236);
  265.     ScreenHDC = MakeWinGDC(rgb, &Screen);
  266.     WindowState = SC_RESTORE;
  267.     Timer     = SetTimer(msg->hwnd, 1, 1, NULL);
  268.     return DefWindowProc(msg->hwnd, msg->msg, msg->wParam, msg->lParam);
  269. }
  270.  
  271. static LRESULT wmDestroy(pMSG msg) {
  272.     KillTimer(msg->hwnd, Timer);
  273.     EndWinGDC(ScreenHDC);
  274.     if (Palette != 0)
  275.         DeleteObject(Palette);
  276.     DestroyIcon(FireIcon);
  277.     return DefWindowProc(msg->hwnd, msg->msg, msg->wParam, msg->lParam);
  278. }
  279.  
  280. static LRESULT wmTimer(pMSG msg) {
  281.     HDC     hdc;
  282.     int     i;
  283.     LPdword p;
  284.     Pdword  q;
  285.     Pbyte   s;
  286.     RECT    r;
  287.  
  288.         // Clean bottom line.
  289.     memset(Buf2 + FIREW*(FIREH-1), 0, FIREW);
  290.         // Set random hot spots and animate.
  291.     for (i = 0; i < 20; i++) {
  292.         int k = rand() % (FIREW-2);
  293.         Buf2[FIREW*FIREH - k] = 235;
  294.     }
  295.     DoFire(Buf1, Buf2);
  296.  
  297.         // Copy buffer to the WinGDC bitmap, adding 10 for the colors.
  298.     p = (LPdword)Screen;
  299.     q = (Pdword)Buf1;
  300.     for (i = 0; i < FIREH*FIREW/4; i++)
  301.         *p++ = *q++ + 0x0a0a0a0a;
  302.  
  303.         // Swap buffers.
  304.     s = Buf1;
  305.     Buf1 = Buf2;
  306.     Buf2 = s;
  307.  
  308.         // Dump bitmap.
  309.     GetClientRect(msg->hwnd, &r);
  310.     hdc = GetDC(msg->hwnd);
  311.     SelectPalette(hdc, Palette, FALSE);
  312.     RealizePalette(hdc);
  313.  
  314.         // If window is not minimized or maximized, do optimal stretch
  315.         // by multiplying by 2^2, else stretch to whatever the size.
  316.         // Vertical stretch can be anything, as it doesn't slow down
  317.         // if it's not stretched by a power of two.
  318.     if (WindowState == SC_MINIMIZE || WindowState == SC_MAXIMIZE)
  319.         WinGStretchBlt(hdc, 0, 0, r.right-r.left, r.bottom-r.top,
  320.                        ScreenHDC, 0, 0, FIREW, FIREH);
  321.     else
  322.         WinGStretchBlt(hdc, 0, 0, WINDOWW, r.bottom-r.top,
  323.                        ScreenHDC, 0, 0, FIREW, FIREH);
  324.     ReleaseDC(msg->hwnd, hdc);
  325.  
  326.     return DefWindowProc(msg->hwnd, msg->msg, msg->wParam, msg->lParam);
  327. }
  328.  
  329. static LRESULT wmQueryNewPalette(pMSG msg) {
  330.     HDC hdc;
  331.     LRESULT f;
  332.  
  333.     hdc = GetDC(msg->hwnd);
  334.     if (Palette)
  335.         SelectPalette(hdc, Palette, FALSE);
  336.     f = RealizePalette(hdc);
  337.     ReleaseDC(msg->hwnd, hdc);
  338.     return f;
  339. }
  340.  
  341. static LRESULT wmSysCommand(pMSG msg) {
  342.     if (msg->wParam == SC_MINIMIZE ||
  343.         msg->wParam == SC_MAXIMIZE ||
  344.         msg->wParam == SC_RESTORE)
  345.         WindowState = msg->wParam;
  346.     return DefWindowProc(msg->hwnd, msg->msg, msg->wParam, msg->lParam);
  347. }
  348.  
  349. static LRESULT wmWindowPosChanging(pMSG msg) {
  350.     LPWINDOWPOS lpwp;
  351.     RECT rw, rc;
  352.     int  x, w;
  353.  
  354.         // If window is not maximized or minimized, align its client
  355.         // area to a four-pixel boundary for optimal performance.
  356.     if (WindowState == SC_RESTORE) {
  357.         lpwp = (LPWINDOWPOS)msg->lParam;
  358.         GetWindowRect(msg->hwnd, &rw);
  359.         GetClientRect(msg->hwnd, &rc);
  360.         w = rw.right - rw.left - (rc.right - rc.left); // Width of frame.
  361.         x = lpwp->x + w;
  362.         lpwp->x = (x & ~3) - w;   // Align it.
  363.         if (lpwp->cx - w > WINDOWW)
  364.             lpwp->cx = w + WINDOWW;
  365.     }
  366.     return DefWindowProc(msg->hwnd, msg->msg, msg->wParam, msg->lParam);
  367. }
  368.  
  369.  
  370.     // Window procedure.
  371. LRESULT CALLBACK FireWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
  372.     tMSG m;
  373.  
  374.     m.hwnd   = hwnd;
  375.     m.msg    = msg;
  376.     m.wParam = wParam;
  377.     m.lParam = lParam;
  378.  
  379.     switch (msg) {
  380.         case WM_CREATE:        return wmCreate(&m);
  381.         case WM_DESTROY:       return wmDestroy(&m);
  382.         case WM_QUERYDRAGICON:
  383.             if (FireIcon != (HICON)NULL)
  384.                 return FireIcon;
  385.             break;
  386.  
  387.         case WM_TIMER: return wmTimer(&m);
  388.  
  389.         case WM_PALETTECHANGED:
  390.             if ((HWND)wParam != hwnd)   // If we changed the palette.
  391.                 return wmQueryNewPalette(&m);
  392.             break;
  393.         case WM_QUERYNEWPALETTE: return wmQueryNewPalette(&m);
  394.  
  395.         case WM_WINDOWPOSCHANGING: return wmWindowPosChanging(&m);
  396.         case WM_SYSCOMMAND:        return wmSysCommand(&m);
  397.  
  398.         case WM_CLOSE:
  399.             PostQuitMessage(0);
  400.             break;
  401.     }
  402.  
  403.     return DefWindowProc(hwnd, msg, wParam, lParam);
  404. }
  405.  
  406. // ===============================================================
  407. // Main entry point.
  408.  
  409. int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) {
  410.     static char ClassName[] = "WinFire";
  411.     static char AppName[]   = "WinFire";
  412.             int w, h;
  413.             MSG msg;
  414.            HWND hwnd;
  415.  
  416.     if (hPrev == 0) {
  417.         WNDCLASS c;
  418.  
  419.         c.hCursor       = LoadCursor(NULL, IDC_WAIT);
  420.         c.hIcon         = NULL;
  421.         c.lpszMenuName  = NULL;
  422.         c.lpszClassName = "WinFire";
  423.         c.hbrBackground = NULL;
  424.         c.hInstance     = hInst;
  425.         c.style         = CS_BYTEALIGNCLIENT | CS_VREDRAW | CS_HREDRAW;
  426.         c.lpfnWndProc   = (WNDPROC)FireWndProc;
  427.         c.cbWndExtra    = 0;
  428.         c.cbClsExtra    = 0;
  429.         if (!RegisterClass(&c))
  430.             return 1;
  431.     }
  432.  
  433.     AppInstance = hInst;
  434.     w = GetSystemMetrics(SM_CXSCREEN);
  435.     h = GetSystemMetrics(SM_CYSCREEN);
  436.  
  437.     hwnd = CreateWindow (ClassName,                // Class name
  438.                          AppName,                  // Caption
  439.                          WS_OVERLAPPEDWINDOW,      // Style bits
  440.                          (w-WINDOWW)/2, (h-WINDOWH)/2, // Position
  441.                          WINDOWW, WINDOWH,             // Size
  442.                          (HWND)NULL,               // Parent window (no parent)
  443.                          (HMENU)NULL,              // no menu
  444.                          hInst,                    // handle to window instance
  445.                          (LPSTR)NULL               // no params to pass on
  446.                         );
  447.     if (hwnd == (HWND)NULL)
  448.         return 1;
  449.     ShowWindow(hwnd, sw);
  450.  
  451.     while (GetMessage(&msg, (HWND)NULL, 0, 0)) {
  452.         TranslateMessage(&msg);
  453.         DispatchMessage(&msg);
  454.     }
  455.  
  456.     return 0;
  457. }
  458.  
  459. // ------------------------ WINFIRE.C ------------------------------
  460.  
  461.